﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Data.SQLite;
using Crawler.DataServices.Persistence.UnitOfWork;
using Crawler.Domain;
using Crawler.Domain.DataEntities;
using Crawler.Domain.DataEntities.Crawling;
using Crawler.DomainServices.DataServices;
using NHibernate;
using StructureMap;

namespace Crawler.DataServices.Repositories
{
	internal class SourceContentRepository : ISourceContentRepository
	{
		public void Save(RawPageCrawlInfo data)
		{
			try
			{
				using (IUnitOfWork uoc = GetUnitOfWork())
				{
					uoc.Session.SaveOrUpdate(data);
					uoc.Commit();
				}
			}
			catch (Exception ex)
			{
				var sqlEx = ex.InnerException as SqlException;
				var sqliteEx = ex.InnerException as SQLiteException;
				if ((sqlEx != null && sqlEx.Number == 2627) || (sqliteEx != null && sqliteEx.ErrorCode == 19)) //unique violation
				{
					return;
				}
				throw;
			}
		}

		public IEnumerable<RawPageCrawlInfo> GetProccessablePages(CrawlingSession crawlingSession,
			ProccessablePageType pageType)
		{
			using (IUnitOfWork uoc = GetUnitOfWork())
			{
				return uoc.Session.QueryOver<RawPageCrawlInfo>()
					.Where(x => x.SessionId == crawlingSession.SessionId && x.ProccessablePageType == pageType).List();
			}
		}


		public int CountByUrl(CrawlingSession session, string url)
		{
			using (IUnitOfWork uoc = GetUnitOfWork())
			{
				return
					uoc.Session.QueryOver<RawPageCrawlInfo>()
						.Where(x => x.SessionId == session.SessionId && x.FromUrl == url)
						.RowCount();
			}
		}

		public int GetProccessablesPagesCount(CrawlingSession session, ProccessablePageType pageType, int sizePage,
			bool proccessed = false)
		{
			using (IUnitOfWork uoc = GetUnitOfWork())
			{
				int rowCount = GetPagesSource(pageType, session, proccessed, uoc).RowCount();
				return (rowCount/sizePage) + 1;
			}
		}

		public IEnumerable<RawPageCrawlInfo> GetProccessablePage(ProccessablePageType pageType, int pageNum,
			CrawlingSession session, int sizePage,
			bool proccessed = false)
		{
			using (IUnitOfWork uoc = GetUnitOfWork())
			{
				IList<RawPageCrawlInfo> result =
					GetPagesSource(pageType, session, proccessed, uoc).Skip(pageNum*sizePage - sizePage).Take(sizePage).List();
				return result;
			}
		}

		public RawPageCrawlInfo GetProccessableContentByUrl(string sessionId, string url)
		{
			using (IUnitOfWork uoc = GetUnitOfWork())
			{
				return uoc.Session.QueryOver<RawPageCrawlInfo>()
					.Where(x => x.SessionId == sessionId && x.FromUrl == url).SingleOrDefault();
			}
		}

		private static IUnitOfWork GetUnitOfWork()
		{
			var uoc = ObjectFactory.GetInstance<IUnitOfWork>();
			uoc.SetToWorkWithContent();
			return uoc;
		}


		private static IQueryOver<RawPageCrawlInfo, RawPageCrawlInfo> GetPagesSource(ProccessablePageType pageType,
			CrawlingSession session, bool proccessed, IUnitOfWork uoc)
		{
			return
				uoc.Session.QueryOver<RawPageCrawlInfo>()
					.Where(x => x.SessionId == session.SessionId && x.ProccessablePageType == pageType && x.Processed == proccessed);
		}
	}
}